package com.reactim.message.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import com.reactim.message.config.validation.ValidConnectionTimeout;
import com.reactim.message.config.validation.ValidRedisKeyPrefix;

/**
 * ReactIM统一配置根类
 * 
 * <p>作为所有ReactIM配置的统一入口，解决Spring Boot配置属性识别问题。
 * 从application.yml中读取reactim.*前缀的所有配置项。</p>
 * 
 * <h3>配置结构</h3>
 * <ul>
 *   <li><strong>消息配置</strong> (reactim.message.*) - 消息撤回、编辑、路由等功能配置</li>
 *   <li><strong>连接配置</strong> (reactim.connection.*) - 连接管理、存储、安全、监控等配置</li>
 *   <li><strong>性能配置</strong> (reactim.performance.*) - 性能监控和测试相关配置</li>
 * </ul>
 * 
 * <h3>使用示例</h3>
 * <pre>{@code
 * @Autowired
 * private ReactimConfig reactimConfig;
 * 
 * public void example() {
 *     // 获取消息撤回时间限制
 *     int recallLimit = reactimConfig.getMessage().getRecallTimeLimit();
 *     
 *     // 检查是否启用分布式存储
 *     boolean distributed = reactimConfig.getConnection().isDistributedStorage();
 *     
 *     // 获取Redis键前缀
 *     String keyPrefix = reactimConfig.getConnection().getRedis().getKeyPrefix();
 * }
 * }</pre>
 * 
 * <h3>配置验证</h3>
 * <p>所有配置项都包含JSR-303验证注解，确保配置值的有效性。
 * 无效的配置会在应用启动时抛出异常。</p>
 * 
 * @author ReactIM Team
 * @version 1.0.0
 * @since 1.0.0
 * @see MessageProperties 消息相关配置
 * @see ConnectionProperties 连接管理相关配置
 * @see PerformanceProperties 性能相关配置
 */
@Configuration
@ConfigurationProperties(prefix = "reactim")
@Validated
@Data
public class ReactimConfig {
    
    /**
     * 消息相关配置
     */
    @Valid
    @NotNull
    private MessageProperties message = new MessageProperties();
    
    /**
     * 连接管理相关配置
     */
    @Valid
    @NotNull
    private ConnectionProperties connection = new ConnectionProperties();
    
    /**
     * 性能监控相关配置
     */
    @Valid
    @NotNull
    private PerformanceProperties performance = new PerformanceProperties();
    
    /**
     * 消息配置属性类
     */
    @Data
    public static class MessageProperties {
        /**
         * 消息撤回时间限制（分钟）
         */
        @Min(value = 1, message = "消息撤回时间限制必须大于0分钟")
        private int recallTimeLimit = 2;
        
        /**
         * 消息编辑时间限制（分钟）
         */
        @Min(value = 1, message = "消息编辑时间限制必须大于0分钟")
        private int editTimeLimit = 5;
        
        /**
         * 消息最大长度
         */
        @Min(value = 1, message = "消息最大长度必须大于0")
        private int maxContentLength = 10000;
        
        /**
         * 文件消息最大大小（MB）
         */
        @Min(value = 1, message = "文件消息最大大小必须大于0MB")
        private int maxFileSize = 100;
        
        /**
         * 消息路由配置
         */
        @Valid
        @NotNull
        private RoutingProperties routing = new RoutingProperties();
        
        /**
         * 路由配置属性类
         */
        @Data
        public static class RoutingProperties {
            /**
             * Kafka配置
             */
            @Valid
            @NotNull
            private KafkaProperties kafka = new KafkaProperties();
            
            /**
             * 重试配置
             */
            @Valid
            @NotNull
            private RetryProperties retry = new RetryProperties();
            
            /**
             * 确认配置
             */
            @Valid
            @NotNull
            private AckProperties ack = new AckProperties();
            
            /**
             * Kafka配置属性类
             */
            @Data
            public static class KafkaProperties {
                /**
                 * 跨实例消息主题
                 */
                @NotBlank(message = "Kafka主题不能为空")
                private String topic = "cross-instance-messages";
                
                /**
                 * 消息确认主题
                 */
                @NotBlank(message = "Kafka确认主题不能为空")
                private String ackTopic = "message-acknowledgments";
            }
            
            /**
             * 重试配置属性类
             */
            @Data
            public static class RetryProperties {
                /**
                 * 最大重试次数
                 */
                @Min(value = 1, message = "最大重试次数必须大于0")
                private int maxAttempts = 3;
            }
            
            /**
             * 确认配置属性类
             */
            @Data
            public static class AckProperties {
                /**
                 * 确认超时时间（秒）
                 */
                @Min(value = 1, message = "确认超时时间必须大于0秒")
                private int timeoutSeconds = 30;
            }
        }
    }
    
    /**
     * 连接配置属性类
     */
    @Data
    public static class ConnectionProperties {
        /**
         * 连接过期时间（分钟）
         */
        @ValidConnectionTimeout(min = 1, max = 1440, message = "连接过期时间必须在1分钟到1440分钟（24小时）之间")
        private int expirationTime = 30;
        
        /**
         * 清理任务执行间隔（分钟）
         */
        @Min(value = 1, message = "清理任务执行间隔必须大于0分钟")
        private int cleanupInterval = 5;
        
        /**
         * 是否启用分布式连接存储
         */
        @NotNull
        private boolean distributedStorage = true;
        
        /**
         * Redis相关配置
         */
        @Valid
        @NotNull
        private RedisProperties redis = new RedisProperties();
        
        /**
         * 安全相关配置
         */
        @Valid
        @NotNull
        private SecurityProperties security = new SecurityProperties();
        
        /**
         * 监控相关配置
         */
        @Valid
        @NotNull
        private MonitoringProperties monitoring = new MonitoringProperties();
        
        /**
         * 缓存相关配置
         */
        @Valid
        @NotNull
        private CacheProperties cache = new CacheProperties();
        
        /**
         * 故障恢复相关配置
         */
        @Valid
        @NotNull
        private FaultRecoveryProperties faultRecovery = new FaultRecoveryProperties();
        
        /**
         * Redis配置属性类
         */
        @Data
        public static class RedisProperties {
            /**
             * Redis键前缀
             */
            @NotBlank(message = "Redis键前缀不能为空")
            @ValidRedisKeyPrefix(requireColonSuffix = true, minLength = 3, maxLength = 100)
            private String keyPrefix = "reactim:connection:";
            
            /**
             * 用户连接前缀
             */
            @NotBlank(message = "用户连接前缀不能为空")
            private String userConnectionPrefix = "user:connection:";
            
            /**
             * 实例连接前缀
             */
            @NotBlank(message = "实例连接前缀不能为空")
            private String instanceConnectionPrefix = "instance:connections:";
            
            /**
             * 在线用户键
             */
            @NotBlank(message = "在线用户键不能为空")
            private String onlineUsersKey = "online:users";
            
            /**
             * 连接信息过期时间（秒）
             */
            @Min(value = 60, message = "连接信息过期时间必须大于60秒")
            private long connectionTtl = 86400; // 默认1天
            
            /**
             * 获取用户连接键
             * @param userId 用户ID
             * @return Redis键
             */
            public String getUserConnectionKey(Long userId) {
                return keyPrefix + userConnectionPrefix + userId;
            }
            
            /**
             * 获取实例连接键
             * @param instanceId 实例ID
             * @return Redis键
             */
            public String getInstanceConnectionsKey(String instanceId) {
                return keyPrefix + instanceConnectionPrefix + instanceId;
            }
            
            /**
             * 获取在线用户键
             * @return Redis键
             */
            public String getOnlineUsersKey() {
                return keyPrefix + onlineUsersKey;
            }
        }
        
        /**
         * 安全配置属性类
         */
        @Data
        public static class SecurityProperties {
            /**
             * 是否启用数据加密
             */
            @NotNull
            private boolean enableEncryption = true;
            
            /**
             * 加密密钥（Base64编码）
             */
            private String encryptionKey = "";
            
            /**
             * 是否启用连接验证
             */
            @NotNull
            private boolean enableValidation = true;
            
            /**
             * 是否启用访问控制
             */
            @NotNull
            private boolean enableAccessControl = true;
            
            /**
             * 每个用户最大连接数
             */
            @Min(value = 1, message = "每个用户最大连接数必须大于0")
            private int maxConnectionsPerUser = 5;
            
            /**
             * 连接间隔限制（秒）
             */
            @Min(value = 0, message = "连接间隔限制不能为负数")
            private int connectionIntervalSeconds = 5;
            
            /**
             * 每个IP最大连接数
             */
            @Min(value = 1, message = "每个IP最大连接数必须大于0")
            private int maxConnectionsPerIp = 20;
            
            /**
             * IP频率限制时间窗口（分钟）
             */
            @Min(value = 1, message = "IP频率限制时间窗口必须大于0分钟")
            private int ipRateLimitWindowMinutes = 10;
            
            /**
             * 是否启用设备验证
             */
            @NotNull
            private boolean enableDeviceValidation = true;
            
            /**
             * 是否启用版本验证
             */
            @NotNull
            private boolean enableVersionValidation = true;
            
            /**
             * 最低客户端版本
             */
            @NotBlank(message = "最低客户端版本不能为空")
            private String minClientVersion = "1.0.0";
            
            /**
             * 权限缓存TTL（分钟）
             */
            @Min(value = 1, message = "权限缓存TTL必须大于0分钟")
            private int permissionCacheTtlMinutes = 30;
        }
        
        /**
         * 监控配置属性类
         */
        @Data
        public static class MonitoringProperties {
            /**
             * 是否启用连接监控
             */
            @NotNull
            private boolean enabled = true;
            
            /**
             * 心跳检测间隔（毫秒）
             */
            @Min(value = 1000, message = "心跳检测间隔必须大于1000毫秒")
            private long heartbeatIntervalMs = 30000;
            
            /**
             * 不活跃阈值（毫秒）
             */
            @Min(value = 10000, message = "不活跃阈值必须大于10000毫秒")
            private long inactivityThresholdMs = 300000;
            
            /**
             * 是否自动移除不活跃连接
             */
            @NotNull
            private boolean autoRemoveInactive = true;
            
            /**
             * 是否自动移除心跳失败的连接
             */
            @NotNull
            private boolean autoRemoveFailedHeartbeat = true;
            
            /**
             * 是否发送实际心跳消息
             */
            @NotNull
            private boolean sendActualHeartbeat = true;
            
            /**
             * 统计报告生成间隔（毫秒）
             */
            @Min(value = 1000, message = "统计报告生成间隔必须大于1000毫秒")
            private long reportIntervalMs = 60000;
            
            /**
             * 是否启用连接事件记录
             */
            @NotNull
            private boolean enableEventLogging = true;
            
            /**
             * 是否启用监控仪表板
             */
            @NotNull
            private boolean enableDashboard = true;
        }
        
        /**
         * 缓存配置属性类
         */
        @Data
        public static class CacheProperties {
            /**
             * 是否启用本地缓存
             */
            @NotNull
            private boolean enabled = true;
            
            /**
             * 连接信息缓存最大容量
             */
            @Min(value = 100, message = "连接信息缓存最大容量必须大于100")
            private int connectionCacheMaxSize = 10000;
            
            /**
             * 连接信息缓存过期时间（秒）
             */
            @Min(value = 10, message = "连接信息缓存过期时间必须大于10秒")
            private int connectionCacheExpireSeconds = 300;
            
            /**
             * 在线状态缓存最大容量
             */
            @Min(value = 100, message = "在线状态缓存最大容量必须大于100")
            private int onlineStatusCacheMaxSize = 20000;
            
            /**
             * 在线状态缓存过期时间（秒）
             */
            @Min(value = 10, message = "在线状态缓存过期时间必须大于10秒")
            private int onlineStatusCacheExpireSeconds = 60;
            
            /**
             * 统计信息缓存过期时间（秒）
             */
            @Min(value = 10, message = "统计信息缓存过期时间必须大于10秒")
            private int statsCacheExpireSeconds = 30;
            
            /**
             * 是否启用缓存预热
             */
            @NotNull
            private boolean enablePreloading = true;
            
            /**
             * 缓存预热批次大小
             */
            @Min(value = 10, message = "缓存预热批次大小必须大于10")
            private int preloadingBatchSize = 1000;
        }
        
        /**
         * 故障恢复配置属性类
         */
        @Data
        public static class FaultRecoveryProperties {
            /**
             * 是否启用故障恢复
             */
            @NotNull
            private boolean enabled = true;
            
            /**
             * 健康检查间隔（毫秒）
             */
            @Min(value = 1000, message = "健康检查间隔必须大于1000毫秒")
            private long healthCheckIntervalMs = 5000;
            
            /**
             * 故障阈值（连续失败次数）
             */
            @Min(value = 1, message = "故障阈值必须大于0")
            private int failureThreshold = 3;
            
            /**
             * 恢复超时时间（毫秒）
             */
            @Min(value = 1000, message = "恢复超时时间必须大于1000毫秒")
            private long recoveryTimeoutMs = 10000;
            
            /**
             * Redis重连间隔（毫秒）
             */
            @Min(value = 1000, message = "Redis重连间隔必须大于1000毫秒")
            private long redisReconnectIntervalMs = 5000;
            
            /**
             * 最大重试次数
             */
            @Min(value = 1, message = "最大重试次数必须大于0")
            private int maxRetryAttempts = 10;
            
            /**
             * 降级到本地存储的阈值
             */
            @Min(value = 1, message = "降级到本地存储的阈值必须大于0")
            private int fallbackThreshold = 3;
        }
    }
    
    /**
     * 性能配置属性类
     */
    @Data
    public static class PerformanceProperties {
        /**
         * 性能报告配置
         */
        @Valid
        @NotNull
        private ReportProperties report = new ReportProperties();
        
        /**
         * 性能测试配置
         */
        @Valid
        @NotNull
        private TestProperties test = new TestProperties();
        
        /**
         * 性能报告配置属性类
         */
        @Data
        public static class ReportProperties {
            /**
             * 是否启用性能报告
             */
            @NotNull
            private boolean enabled = true;
            
            /**
             * 报告生成间隔（毫秒）
             */
            @Min(value = 1000, message = "报告生成间隔必须大于1000毫秒")
            private long interval = 300000; // 5分钟
        }
        
        /**
         * 性能测试配置属性类
         */
        @Data
        public static class TestProperties {
            /**
             * 最大连接数
             */
            @Min(value = 1, message = "最大连接数必须大于0")
            private int maxConnections = 100000;
            
            /**
             * 批次大小列表
             */
            @NotNull
            private int[] batchSizes = {1000, 5000, 10000, 20000};
            
            /**
             * 线程数列表
             */
            @NotNull
            private int[] threadCounts = {5, 10, 20, 50, 100};
            
            /**
             * 操作超时时间（秒）
             */
            @Min(value = 1, message = "操作超时时间必须大于0秒")
            private int operationTimeoutSeconds = 30;
            
            /**
             * 测试超时时间（分钟）
             */
            @Min(value = 1, message = "测试超时时间必须大于0分钟")
            private int testTimeoutMinutes = 30;
            
            /**
             * 是否在测试后清理
             */
            @NotNull
            private boolean cleanupAfterTest = true;
            
            /**
             * 清理超时时间（分钟）
             */
            @Min(value = 1, message = "清理超时时间必须大于0分钟")
            private int cleanupTimeoutMinutes = 5;
            
            /**
             * 是否生成详细报告
             */
            @NotNull
            private boolean generateDetailedReport = true;
            
            /**
             * 是否导出指标
             */
            @NotNull
            private boolean exportMetrics = true;
        }
    }
}